﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Net;
using System.Security.Principal;
using System.IO;
using System.Net.Sockets;
using System.Text.RegularExpressions;
using System.Security;
using System.Net.NetworkInformation;

namespace Com.CodePlex.SPPower.Service {

	public class AutomationService {

		public IList<CmdParameter> GetParameters(Model.Cmd cmd) {
			List<CmdParameter> paras = new List<CmdParameter>();
			using (PowerShell ps = PowerShell.Create()) {
				PSSnapInException ex = null;
				try {
					ps.Runspace.RunspaceConfiguration.AddPSSnapIn("Microsoft.SharePoint.PowerShell", out ex);
				} catch (PSArgumentException ex2) {
					int i = 0;
				}
				ps.AddScript(@"
(Get-Command " + cmd.Name + @").Parameters
");
				var results = ps.Invoke<Dictionary<string, ParameterMetadata>>();
				foreach (Dictionary<string, ParameterMetadata> item in results) {
					if (item != null) {
						item.Keys.ToList().ForEach(i => {
							paras.Add(new CmdParameter() { Name = item[i].Name, Type = item[i].ParameterType, Value = "" });
						});
					} else {
						return null;
					}
				}
			}
			return paras;
		}

		public IList<string> GetNoCategoryCmds() {
			List<string> cmds = new List<string>();
			Comparer<string> compare = new Comparer<string>((x, y) => x.ToLower() == y.ToLower());
			IList<string> cmdswithcat = new Data.CmdRepository().FindCommandsWithCategory();
			using (PowerShell ps = PowerShell.Create()) {
				PSSnapInException ex = null;
				try {
					ps.Runspace.RunspaceConfiguration.AddPSSnapIn("Microsoft.SharePoint.PowerShell", out ex);
					ps.AddScript(@"
Get-Command –PSSnapin 'Microsoft.SharePoint.PowerShell'
");
				} catch(PSArgumentException ex2) {
					ps.AddScript("Get-Command *get-c*");
				}
				var results = ps.Invoke<CommandInfo>();
				foreach (CommandInfo item in results) {
					if (!cmdswithcat.Contains(item.Name, compare)) {
						cmds.Add(item.Name);
					}
				}
			}
            //System.Threading.Thread.Sleep(10000);
			return cmds;
		}

		class Comparer<T> : IEqualityComparer<T> {
			private readonly Func<T, T, bool> _comparer;
			public Comparer(Func<T, T, bool> comparer) {
				if (comparer == null) {
					throw new ArgumentNullException("comparer");
				}
				_comparer = comparer;
			}
			public bool Equals(T x, T y) {
				return _comparer(x, y);
			}
			public int GetHashCode(T obj) {
				return obj.ToString().ToLower().GetHashCode();
			}
		}

		public IList<string> RunPowerShellScript(string cmd, IList<CmdParameter> paras) {
			List<string> results = new List<string>();
			using (PowerShell ps = PowerShell.Create()) { //todo: make own host, so can stream output
				PSSnapInException ex = null;
				try {
					ps.Runspace.RunspaceConfiguration.AddPSSnapIn("Microsoft.SharePoint.PowerShell", out ex);
				} catch (PSArgumentException ex2) {
					int i = 0;
				}
				ps.Streams.Debug.DataAdded += (s, e) => {
					int k = 0;
				};
				ps.Streams.Error.DataAdded += (s, e) => {
					System.Management.Automation.PSDataCollection<System.Management.Automation.ErrorRecord> s1 = s as System.Management.Automation.PSDataCollection<System.Management.Automation.ErrorRecord>;
					int k = 0;
				};
				ps.Streams.Progress.DataAdded += (s, e) => {
					int k = 0;
				};
				ps.Streams.Verbose.DataAdded += (s, e) => {
					int k = 0;
				};
				ps.Streams.Warning.DataAdded += (s, e) => {
					int k = 0;
				};
				ps.AddCommand(cmd);
				//ps.AddScript("get-process |% {$_}");
				paras.ToList().ForEach(i => {
					if (i.Value != null) {
						ps.AddParameter(i.Name, i.Value);
					}
				});
				try {
					/*
					PSDataCollection<string> input = new PSDataCollection<string>();
					PSDataCollection<string> output = new PSDataCollection<string>();
					output.DataAdded += (s, e) => {
						int j = 0;
					};
					IAsyncResult result = ps.BeginInvoke<string, string>(
						input, output, new PSInvocationSettings() { },
						(ar) => {
							int i = 0;
							ps.EndInvoke(ar); 
						}, null);
					*/
					var output = ps.Invoke<string>();
					foreach (var item in output) {
						results.AddRange(item.ToString().Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries));
					}
					foreach (var item in ps.Streams.Error) {
						results.AddRange(item.ToString().Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries));
					}
				} catch (PSSecurityException sex) {
					results.Add(sex.ToString());
				}
			}
			return results;
		}
	}

	public class CmdParameter {
		public Type Type;
		public string Name;
		public object Value;
		public bool Mandatory;
	}
}